﻿using Newtonsoft.Json;
using System.Linq.Expressions;
using System.Reflection;
using XYS.Service.Core.Util.Helper;

namespace XYS.Core.Util;

public static partial class Extention
{
    /// <summary>
    /// 序列化设置， 请在Program.cs中对这个属性进行设置（会被请在Program.cs覆盖）
    /// </summary>
    public static JsonSerializerSettings jsonSerializerSettings = new();

    /// <summary>
    /// 构造函数
    /// </summary>
    static Extention()
    {
        JsonSerializerSettings setting = new();
        JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
        {
            //日期类型默认格式化处理
            setting.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
            setting.DateFormatString = "yyyy-MM-dd HH:mm:ss.fff";
            return setting;
        });
    }


    /// <summary>
    /// 修改匿名对象的值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TProperty"></typeparam>
    /// <param name="instance"></param>
    /// <param name="propExpression"></param>
    /// <param name="newValue"></param>
    /// <returns></returns>
    /// <exception cref="NotSupportedException"></exception>
    public static T Set<T, TProperty>(this T instance, Expression<Func<T, TProperty>> propExpression, TProperty newValue) where T : class
    {
        if (propExpression.Body is not MemberExpression memberExpression) return instance;

        var pi = memberExpression.Member;
        string[] BackingFieldFormats = { "<{0}>i__Field", "<{0}>" };
        var backingFieldNames = BackingFieldFormats.Select(x => string.Format(x, pi.Name)).ToList();
        var fi = typeof(T)
            .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
            .FirstOrDefault(f => backingFieldNames.Contains(f.Name)) ?? throw new NotSupportedException(string.Format("Cannot find backing field for {0}", pi.Name));

        fi.SetValue(instance, newValue);
        return instance;
    }


    /// <summary>
    /// 设置某个字段的值
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="propertyName"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static object SetFieldValue(this object entity, string propertyName, object value)
    {
        var properties = entity.GetType().GetProperties();
        if (properties == null || properties.Length == 0) return entity;
        var property = properties.FirstOrDefault(x => x.Name == propertyName && x.CanWrite == true);
        if (property == null) return entity;
        property.SetValue(entity, value);
        return entity;
    }

    /// <summary>
    /// 设置某个字段的值
    /// </summary>
    /// <param name="entity"></param>
    /// <param name="propertyName"></param>
    /// <returns></returns>
    public static object GetFieldValue(this object entity, string propertyName)
    {
        var properties = entity.GetType().GetProperties();
        if (properties == null || properties.Length == 0) return null;
        var property = properties.FirstOrDefault(x => x.Name == propertyName && x.CanRead == true);
        if (property == null) return null;

        return property.GetValue(entity, null);
    }




    /// <summary>
    /// 设置某个字段的值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <param name="entity"></param>
    /// <param name="propertySelector"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T SetFieldValue<T, TValue>(this T entity, Expression<Func<T, TValue>> propertySelector, TValue value)
    {
        // 获取 Lambda 表达式的成员访问表达式
        var memberExpr = (System.Linq.Expressions.MemberExpression)propertySelector.Body;
        // 获取成员的信息
        var propertyInfo = (PropertyInfo)memberExpr.Member;
        // 设置属性值
        propertyInfo.SetValue(entity, value);

        return entity;
    }

    /// <summary>
    /// 设置某个字段的值
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <param name="entites"></param>
    /// <param name="propertySelector"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static List<T> SetFieldValue<T, TValue>(this List<T> entites, Expression<Func<T, TValue>> propertySelector, TValue value)
    {
        // 获取 Lambda 表达式的成员访问表达式
        var memberExpr = (System.Linq.Expressions.MemberExpression)propertySelector.Body;
        // 获取成员的信息
        var propertyInfo = (PropertyInfo)memberExpr.Member;

        // 设置属性值
        for (int i = 0; i < entites.Count; i++)
            propertyInfo.SetValue(entites[i], value);
        return entites;
    }

    /// <summary>
    /// 标记 添加字段
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    /// <param name="entity"></param>
    /// <param name="condition"></param>
    /// <param name="propertySelector"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T SetFieldValueIF<T, TValue>(this T entity, bool condition, Expression<Func<T, TValue>> propertySelector, Lazy<TValue> value) where T : class
    {
        return condition ? entity.SetFieldValue(propertySelector, value.Value) : entity;
    }


    /// <summary>
    /// 将对象序列化成Json字符串
    /// </summary>
    /// <param name="obj">需要序列化的对象</param>
    /// <returns></returns>
    public static string ToJson(this object obj)
    {
        return JsonConvert.SerializeObject(obj, jsonSerializerSettings);
    }

    /// <summary>
    /// 将Json字符串反序列化为对象
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    /// <param name="jsonStr">Json字符串</param>
    /// <returns></returns>
    public static T ToObject<T>(this string jsonStr)
    {
        try
        {
            //硬编码排除一个常规且很难排查的问题。 后续改进
            if (jsonStr == "保存成功") return (T)(jsonStr as object);
            return JsonConvert.DeserializeObject<T>(jsonStr);
        }
        catch
        {
            try
            {
                string json = jsonStr.Replace("\\\\\"", "\\\"");
                return JsonConvert.DeserializeObject<T>(json);
            }
            catch (Exception ex)
            {
                string content;
                if (string.IsNullOrWhiteSpace(jsonStr)) content = "json为空";
                else content = jsonStr;

                LogHelper.AddLog("Json2Object.log", $"Json转换对象失败，\r\nJson:{content}\r\nType:{typeof(T).FullName}\r\nMessage:{ex.Message}\r\nStackTrace:{ex.StackTrace}");
                throw;
            }
        }
    }

    /// <summary>
    /// 将Json字符串反序列化为对象
    /// </summary>
    /// <param name="jsonStr">json字符串</param>
    /// <param name="type">对象类型</param>
    /// <returns></returns>
    public static object ToObject(this string jsonStr, Type type)
    {
        try
        {
            //硬编码排除一个常规且很难排查的问题。 后续改进
            if (jsonStr == "保存成功") return jsonStr;
            return JsonConvert.DeserializeObject(jsonStr, type);
        }
        catch
        {
            try
            {
                try
                {
                    string json = jsonStr.Replace("\\\\\"", "\\\"");
                    return JsonConvert.DeserializeObject(json, type);
                }
                catch
                {
                    string json = jsonStr.Replace("\\\\\"", "\\\"");
                    return JsonConvert.DeserializeObject(json, type);
                }
            }
            catch (Exception ex)
            {
                string content;
                if (string.IsNullOrWhiteSpace(jsonStr)) content = "json为空";
                else content = jsonStr;

                LogHelper.AddLog("Json2Object.log", $"Json转换对象失败，\r\nJson:{content}\r\nType:{type.FullName}\r\nMessage:{ex.Message}\r\nStackTrace:{ex.StackTrace}");
                throw;
            }
        }
    }


    /// <summary>
    /// 深度复制对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    public static T Clone<T>(this T source)
    {
        // 如果源为null，返回也是null
        if (source is null) return default;
        // 序列化 -> 反序列化
        return source.ToJson().ToObject<T>();
    }
}